package joe.works.cacheimpl;

import java.util.HashMap;
import java.util.List;
import java.util.Map;

import joe.works.cache.CacheEvent;
import joe.works.cache.ICache;
import joe.works.cache.ICahceListener;
import joe.works.commons.IConvertor;
import joe.works.commons.IKeyValuePair;

/**
 * An implementation of {@link IKeyValuePair} over a {@link ICache} 
 * @author josseyj
 *
 * @param <KeyType>
 * @param <ValueType>
 */
public class KeyValueCache<KeyType, ValueType> implements IKeyValuePair<KeyType, ValueType>, ICahceListener {
	private Map<KeyType, ValueType> values = new HashMap<KeyType, ValueType>();
	private ICache<ValueType> cache;
	private IConvertor<ValueType, KeyType> keyGenerator;
	
	public KeyValueCache(ICache<ValueType> cache, IConvertor<ValueType, KeyType> keyGenerator) {
		this.cache = cache;
		this.keyGenerator = keyGenerator;
	}
	
	public void initialize() {
		if(this.cache.isLoaded()) {
			load();
		}
		this.cache.addCacheListener(this);
	}
	
	public void cacheUpdated(CacheEvent<?> cacheEvent) {
		if(cacheEvent.getCache() == cache) {
			load();
		}
	}
	protected synchronized void load() {
		cache.removeCacheListener(this); //stop listening, the next line might update the cache
		List<ValueType> items = cache.getItems();
		cache.addCacheListener(this);
		values.clear();
		for(ValueType item : items) {
			KeyType key = createKey(item);
			values.put(key, item);
		}
	}
	
	protected KeyType createKey(ValueType value) {
		return keyGenerator.convert(value);
	}
	
	private boolean shouldLoad() {
		return !cache.isLoaded() || cache.isExpired();
	}
	
	public synchronized ValueType getValue(KeyType key) {
		if(shouldLoad()) {
			load();
		}
		return values.get(key);
	}

}
